package com.eu.mybatis.config;

import java.sql.Connection;
import java.util.List;

import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.RowBounds;

import com.eu.mybatis.helper.InterceptorHelper;

public class InterceptorConfig {

	private Dialect dialect;
	
	private StatementHandler statementHandler;
	
	private MetaObject metaObject;

	private boolean delegate;
	
	private BoundSql boundSql;
	
	private MappedStatement mappedStatement;
	
	private RowBounds rowBounds;
	
	public InterceptorConfig(Invocation invocation, Dialect dialect) {
		this.dialect = dialect;
		statementHandler = InterceptorHelper.getStatementHandler(invocation);
		metaObject = SystemMetaObject.forObject(statementHandler);
		delegate = InterceptorHelper.isDelegate(statementHandler);
		boundSql = InterceptorHelper.getBoundSql(delegate, metaObject);
		InterceptorHelper.setValue(metaObject, delegate, "boundSql.sql", InterceptorHelper.formatSql(boundSql.getSql()));
		mappedStatement = (MappedStatement) InterceptorHelper.getValue(metaObject, delegate, "mappedStatement");
		rowBounds = InterceptorHelper.getValue(metaObject, delegate, "rowBounds");
	}

	public StatementHandler getStatementHandler() {
		return statementHandler;
	}

	public void setStatementHandler(StatementHandler statementHandler) {
		this.statementHandler = statementHandler;
	}

	public MetaObject getMetaObject() {
		return metaObject;
	}

	public void setMetaObject(MetaObject metaObject) {
		this.metaObject = metaObject;
	}

	public boolean isDelegate() {
		return delegate;
	}

	public void setDelegate(boolean delegate) {
		this.delegate = delegate;
	}

	public BoundSql getBoundSql() {
		return boundSql;
	}

	public void setBoundSql(BoundSql boundSql) {
		this.boundSql = boundSql;
	}

	public MappedStatement getMappedStatement() {
		return mappedStatement;
	}

	public void setMappedStatement(MappedStatement mappedStatement) {
		this.mappedStatement = mappedStatement;
	}

	public String getMappedId() {
		return this.mappedStatement.getId();
	}
	
	public String getSql() {
		return this.boundSql.getSql();
	}
	
	public Object getParameterObject() {
		return statementHandler.getParameterHandler().getParameterObject();
	}
	
	public Configuration getConfiguration() {
		return InterceptorHelper.getValue(metaObject, delegate, "configuration");
	}
	
	public List<ParameterMapping> getParameterMappings() {
		return boundSql.getParameterMappings();
	}
	
	public void setTotalRows(Invocation invocation) throws Exception {
		if(rowBounds != null && rowBounds != RowBounds.DEFAULT) {
			Connection connection = (Connection) invocation.getArgs()[0];
			String sql = this.getSql();
			BoundSql countBoundSql = new BoundSql(getConfiguration(), sql, getParameterMappings(), getParameterObject());
			InterceptorHelper.setTotalRows(connection, this.dialect.getCountSql(sql), this.getParameterObject(), countBoundSql, this.getMappedStatement());
		}
	}
	
	public void resetLogicPageSql() {
		if(rowBounds != null && rowBounds != RowBounds.DEFAULT) {
			setValue("boundSql.sql", this.dialect.getLimitString(getSql(), rowBounds.getOffset(), rowBounds.getLimit()));
			// 采用物理分页后，就不需要mybatis的内存分页了，所以重置下面的两个参数
			setValue("rowBounds.offset", RowBounds.NO_ROW_OFFSET);
			setValue("rowBounds.limit", RowBounds.NO_ROW_LIMIT);
		}
	}
	
	public void setValue(String key, Object value) {
		InterceptorHelper.setValue(metaObject, delegate, key, value);
	}

}
